unit mapedithelper;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, fpjson, tileselectionunit, constants, fgl;

{ TODO: update all this to use different tools (pencil, rect, ellipse) }

type
  TPointList = specialize TFPGList<TPoint>;

  { TAutotileShaper }

  TAutotileShaper = class
    private
      Map: TJSONObject;
      Z: Integer;
      Width, Height: Integer;
      MapData: TJSONArray;
      CellsToCheck: TPointList;
      function GetAutotileSurroundings(X, Y: Integer;
        IsWaterfall: Boolean = False): Byte;
      function TileAt(X, Y: Integer): Integer;  inline;
    public
      constructor Create(AMap: TJSONObject; AZ: Integer);
      destructor Destroy; override;
      procedure QueueCell(X, Y: Integer);
      procedure QueueRectangleCells(X1, Y1, X2, Y2: Integer);
      procedure ChangeCells;
  end;

procedure PlaceMapTile(Map: TJSONObject; Selection: TTileSelection;
  X, Y: Integer; ShiftX, ShiftY: Integer; Layer: Integer);
procedure PlaceMapPencil(Map: TJSONObject; Selection: TTileSelection;
  X, Y: Integer; ShiftX, ShiftY: Integer; Layer: Integer;
  PreciseShapes: Boolean);

const
  FLOOR_AUTOTILE_SHAPE_FROM_SURROUNDINGS: array [0..255] of Byte =
    { 000 000 000 000 000 000 000 000
      0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
      000 001 010 011 100 101 110 111}
    ( 46, 46, 42, 42, 46, 46, 42, 42,
    { 000 000 000 000 000 000 000 000
      0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
      000 001 010 011 100 101 110 111}
      43, 43, 35, 34, 43, 43, 35, 34,
    { 000 000 000 000 000 000 000 000
      1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
      000 001 010 011 100 101 110 111}
      45, 45, 37, 37, 45, 45, 36, 36,
    { 000 000 000 000 000 000 000 000
      1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
      000 001 010 011 100 101 110 111}
      33, 33, 23, 22, 33, 33, 21, 20,
    { 001 001 001 001 001 001 001 001
      0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
      000 001 010 011 100 101 110 111}
      46, 46, 42, 42, 46, 46, 42, 42,
    { 001 001 001 001 001 001 001 001
      0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
      000 001 010 011 100 101 110 111}
      43, 43, 35, 34, 43, 43, 35, 34,
    { 001 001 001 001 001 001 001 001
      1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
      000 001 010 011 100 101 110 111}
      45, 45, 37, 37, 45, 45, 36, 36,
    { 001 001 001 001 001 001 001 001
      1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
      000 001 010 011 100 101 110 111}
      33, 33, 23, 22, 33, 33, 21, 20,
    { 010 010 010 010 010 010 010 010
      0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
      000 001 010 011 100 101 110 111}
      44, 44, 32, 32, 44, 44, 32, 32,
    { 010 010 010 010 010 010 010 010
      0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
      000 001 010 011 100 101 110 111}
      41, 41, 19, 17, 41, 41, 19, 17,
    { 010 010 010 010 010 010 010 010
      1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
      000 001 010 011 100 101 110 111}
      39, 39, 27, 27, 39, 39, 26, 26,
    { 010 010 010 010 010 010 010 010
      1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
      000 001 010 011 100 101 110 111}
      31, 31, 15, 11, 31, 31,  7,  3,
    { 011 011 011 011 011 011 011 011
      0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
      000 001 010 011 100 101 110 111}
      44, 44, 32, 32, 44, 44, 32, 32,
    { 011 011 011 011 011 011 011 011
      0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
      000 001 010 011 100 101 110 111}
      40, 40, 18, 16, 40, 40, 18, 16,
    { 011 011 011 011 011 011 011 011
      1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
      000 001 010 011 100 101 110 111}
      39, 39, 27, 27, 39, 39, 26, 26,
    { 011 011 011 011 011 011 011 011
      1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
      000 001 010 011 100 101 110 111}
      29, 29, 13,  9, 29, 29,  5,  1,
    { 100 100 100 100 100 100 100 100
      0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
      000 001 010 011 100 101 110 111}
      46, 46, 42, 42, 46, 46, 42, 42,
    { 100 100 100 100 100 100 100 100
      0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
      000 001 010 011 100 101 110 111}
      43, 43, 35, 34, 43, 43, 35, 34,
    { 100 100 100 100 100 100 100 100
      1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
      000 001 010 011 100 101 110 111}
      45, 45, 37, 37, 45, 45, 36, 36,
    { 100 100 100 100 100 100 100 100
      1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
      000 001 010 011 100 101 110 111}
      33, 33, 23, 22, 33, 33, 21, 20,
    { 101 101 101 101 101 101 101 101
      0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
      000 001 010 011 100 101 110 111}
      46, 46, 42, 42, 46, 46, 42, 42,
    { 101 101 101 101 101 101 101 101
      0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
      000 001 010 011 100 101 110 111}
      43, 43, 35, 34, 43, 43, 35, 34,
    { 101 101 101 101 101 101 101 101
      1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
      000 001 010 011 100 101 110 111}
      45, 45, 37, 37, 45, 45, 36, 36,
    { 101 101 101 101 101 101 101 101
      1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
      000 001 010 011 100 101 110 111}
      33, 33, 23, 22, 33, 33, 21, 20,
    { 110 110 110 110 110 110 110 110
      0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
      000 001 010 011 100 101 110 111}
      44, 44, 32, 32, 44, 44, 32, 32,
    { 110 110 110 110 110 110 110 110
      0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
      000 001 010 011 100 101 110 111}
      41, 41, 19, 17, 41, 41, 19, 17,
    { 110 110 110 110 110 110 110 110
      1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
      000 001 010 011 100 101 110 111}
      38, 38, 25, 25, 38, 38, 24, 24,
    { 110 110 110 110 110 110 110 110
      1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
      000 001 010 011 100 101 110 111}
      30, 30, 14, 10, 30, 30,  6,  2,
    { 111 111 111 111 111 111 111 111
      0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
      000 001 010 011 100 101 110 111}
      44, 44, 32, 32, 44, 44, 32, 32,
    { 111 111 111 111 111 111 111 111
      0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
      000 001 010 011 100 101 110 111}
      40, 40, 18, 16, 40, 40, 18, 16,
    { 111 111 111 111 111 111 111 111
      1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
      000 001 010 011 100 101 110 111}
      38, 38, 25, 25, 38, 38, 24, 24,
    { 111 111 111 111 111 111 111 111
      1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
      000 001 010 011 100 101 110 111}
      28, 28, 12,  8, 28, 28,  4,  0);

  WALL_AUTOTILE_SHAPE_FROM_SURROUNDINGS: array [0..255] of Byte =
    { 000 000 000 000 000 000 000 000
      0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
      000 001 010 011 100 101 110 111}
    ( 15, 15, 7,  7,  15, 15, 7,  7,
    { 000 000 000 000 000 000 000 000
      0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
      000 001 010 011 100 101 110 111}
      11, 15, 7,  3,  11, 15, 7,  3,
    { 000 000 000 000 000 000 000 000
      1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
      000 001 010 011 100 101 110 111}
      14, 14, 7,  7,  15, 15, 6,  6,
    { 000 000 000 000 000 000 000 000
      1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
      000 001 010 011 100 101 110 111}
      10, 14, 7,  3,  11, 15, 6,  2,
    { 001 001 001 001 001 001 001 001
      0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
      000 001 010 011 100 101 110 111}
      15, 15, 7,  7,  15, 15, 7,  7,
    { 001 001 001 001 001 001 001 001
      0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
      000 001 010 011 100 101 110 111}
      15, 15, 7,  7,  15, 15, 7,  7,
    { 001 001 001 001 001 001 001 001
      1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
      000 001 010 011 100 101 110 111}
      14, 14, 7,  7,  15, 15, 6,  6,
    { 001 001 001 001 001 001 001 001
      1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
      000 001 010 011 100 101 110 111}
      14, 14, 7,  7,  15, 15, 6,  6,
    { 010 010 010 010 010 010 010 010
      0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
      000 001 010 011 100 101 110 111}
      13, 13, 5,  5,  13, 13, 5,  5,
    { 010 010 010 010 010 010 010 010
      0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
      000 001 010 011 100 101 110 111}
      13, 13, 5,  5,  13, 13, 5,  5,
    { 010 010 010 010 010 010 010 010
      1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
      000 001 010 011 100 101 110 111}
      13, 13, 5,  5,  13, 13, 5,  5,
    { 010 010 010 010 010 010 010 010
      1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
      000 001 010 011 100 101 110 111}
      13, 13, 5,  5,  13, 13, 5,  5,
    { 011 011 011 011 011 011 011 011
      0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
      000 001 010 011 100 101 110 111}
      13, 13, 5,  5,  13, 13, 5,  5,
    { 011 011 011 011 011 011 011 011
      0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
      000 001 010 011 100 101 110 111}
      9,  13, 5,  1,  9,  13, 5,  1,
    { 011 011 011 011 011 011 011 011
      1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
      000 001 010 011 100 101 110 111}
      13, 13, 5,  5,  13, 13, 5,  5,
    { 011 011 011 011 011 011 011 011
      1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
      000 001 010 011 100 101 110 111}
      9,  13, 5,  1,  9,  13, 5,  1,
    { 100 100 100 100 100 100 100 100
      0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
      000 001 010 011 100 101 110 111}
      15, 15, 7,  7,  15, 15, 7,  7,
    { 100 100 100 100 100 100 100 100
      0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
      000 001 010 011 100 101 110 111}
      11, 15, 7,  3,  11, 15, 7,  3,
    { 100 100 100 100 100 100 100 100
      1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
      000 001 010 011 100 101 110 111}
      15, 15, 7,  7,  15, 15, 7,  7,
    { 100 100 100 100 100 100 100 100
      1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
      000 001 010 011 100 101 110 111}
      11, 15, 7,  3,  11, 15, 7,  3,
    { 101 101 101 101 101 101 101 101
      0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
      000 001 010 011 100 101 110 111}
      15, 15, 7,  7,  15, 15, 7,  7,
    { 101 101 101 101 101 101 101 101
      0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
      000 001 010 011 100 101 110 111}
      15, 15, 7,  7,  15, 15, 7,  7,
    { 101 101 101 101 101 101 101 101
      1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
      000 001 010 011 100 101 110 111}
      15, 15, 7,  7,  15, 15, 7,  7,
    { 101 101 101 101 101 101 101 101
      1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
      000 001 010 011 100 101 110 111}
      15, 15, 7,  7,  15, 15, 7,  7,
    { 110 110 110 110 110 110 110 110
      0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
      000 001 010 011 100 101 110 111}
      13, 13, 5,  5,  13, 13, 5,  5,
    { 110 110 110 110 110 110 110 110
      0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
      000 001 010 011 100 101 110 111}
      13, 13, 5,  5,  13, 13, 5,  5,
    { 110 110 110 110 110 110 110 110
      1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
      000 001 010 011 100 101 110 111}
      12, 12, 5,  5,  13, 13, 4,  4,
    { 110 110 110 110 110 110 110 110
      1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
      000 001 010 011 100 101 110 111}
      12, 12, 5,  5,  13, 13, 4,  4,
    { 111 111 111 111 111 111 111 111
      0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
      000 001 010 011 100 101 110 111}
      13, 13, 5,  5,  13, 13, 5,  5,
    { 111 111 111 111 111 111 111 111
      0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
      000 001 010 011 100 101 110 111}
      9,  13, 5,  1,  9,  13, 5,  1,
    { 111 111 111 111 111 111 111 111
      1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
      000 001 010 011 100 101 110 111}
      12, 12, 5,  5,  13, 13, 4,  4,
    { 111 111 111 111 111 111 111 111
      1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
      000 001 010 011 100 101 110 111}
      8,  12, 5,  1,  9,  13, 4,  0);

  WATERFALL_AUTOTILE_SHAPE_FROM_SURROUNDINGS: array [0..3] of Byte =
    { 0 0  0 1  1 0  1 1 }
    (  3,   1,   2,   0);

implementation

uses
  Math, autotilehelper, globals;

procedure PlaceMapTile(Map: TJSONObject; Selection: TTileSelection; X,
  Y: Integer; ShiftX, ShiftY: Integer; Layer: Integer);

  procedure SetTileValue(Z, TileId: Integer);
  var
    Index: Integer;
  begin
    Index := (Z * Map.Integers['height'] + Y) * Map.Integers['width'] + X;
    Map.Arrays['data'].Integers[Index] := TileId;
  end;

  function OldTileAt(Z: Integer): Integer;
  var
    Index: Integer;
  begin
    Index := (Z * Map.Integers['height'] + Y) * Map.Integers['width'] + X;
    OldTileAt := Map.Arrays['data'].Integers[Index];
  end;

var
  I: Integer;
  ShiftedX, ShiftedY: Integer;
  Value: Integer;
begin
  ShiftedX := ShiftX mod Selection.Width;
  while ShiftedX < 0 do
    ShiftedX := ShiftedX + Selection.Width;

  ShiftedY := ShiftY mod Selection.Height;
  while ShiftedY < 0 do
    ShiftedY := ShiftedY + Selection.Height;

  if (Y < 0) or (X < 0) or (X >= Map.Integers['width'])
                    or (Y >= Map.Integers['height']) then
     Exit;

  if Layer = LAYER_ALL then begin
    for I := 0 to 4 do begin
      Value := Selection.Data[I, ShiftedX, ShiftedY];
      if Value <> 0 then begin
        if (I = 3) and (OldTileAt(3) <> 0) and (OldTileAt(3) <> Value)
           and (Value <> TILE_ID_ERASER) then
          SetTileValue(2, OldTileAt(3));

        if Value = TILE_ID_ERASER then
          SetTileValue(I, 0)
        else
          SetTileValue(I, Value);
      end;
      {TODO: add special handling for L2 L3}
      {TODO: add autotiles}
    end;
  end
  else begin
    SetTileValue(Layer, Selection.Data[0, ShiftedX, ShiftedY]);
  end;

end;

procedure PlaceMapPencil(Map: TJSONObject; Selection: TTileSelection; X,
  Y: Integer; ShiftX, ShiftY: Integer; Layer: Integer; PreciseShapes: Boolean);
var
  SelectionX, SelectionY: Integer;
  EndX, EndY: Integer;

  procedure ReshapeLayer(ReshapedLayer: Integer);
  var
    Shaper: TAutotileShaper;
  begin
    Shaper := TAutotileShaper.Create(Map, ReshapedLayer);
    Shaper.QueueRectangleCells(X, Y, X + Selection.Width - 1,
                                     Y + Selection.Height - 1);
    Shaper.ChangeCells;
    Shaper.Free
  end;

begin
  if Selection = nil then
    Exit;

  EndX := Min(Selection.Width -1, Map.Integers['width'] - ShiftX);
  EndY := Min(Selection.Height -1, Map.Integers['height'] - ShiftY);

  for SelectionX := 0 to EndX do
    for SelectionY := 0 to EndY do begin
      PlaceMapTile(Map, Selection, X+SelectionX, Y+SelectionY,
                        ShiftX+SelectionX, ShiftY+SelectionY, Layer);
      if not PreciseShapes then begin
        {TODO: do autotile shape selection}
        if Layer = LAYER_ALL then begin
          ReshapeLayer(0);
          ReshapeLayer(1);
        end else begin
          ReshapeLayer(Layer);
        end;
      end;

    end;

  Game.MapIsDirty := True;
end;

{ TAutotileShaper }

function TAutotileShaper.GetAutotileSurroundings(X, Y: Integer;
  IsWaterfall: Boolean = False): Byte;
var
  TileId1: Integer;

  function BitFor(X2, Y2: Integer): Integer;
  var
    TileId2: Integer;
  begin
    if (X2 < 0) or (Y2 < 0) or (X2 >= Width) or (Y2 >= Height) then begin
      BitFor := 1;
    end else begin
      TileId2 := TileAt(X2, Y2);
      if IsSameKindTile(TileId1, TileId2) then
        BitFor := 1
      else if IsWaterfallTile(TileId2) and (IsWaterBodyTile(TileId1) or IsWaterfallTile(TileId1))  then
        BitFor := 1
      else if IsWaterfallTile(TileId1) and (IsWaterBodyTile(TileId2) or IsWaterfallTile(TileId2))  then
        BitFor := 1
        {TODO: understand why first water doesn't get united with waterfalls}
      else
        BitFor := 0;
    end;
  end;

begin
  TileId1 := TileAt(X, Y);

  { The bits are numbered like this:
    765
    4 3
    210 }

  if IsWaterfall then
    GetAutotileSurroundings := (BitFor(X-1, Y) shl 1) or BitFor(X+1, Y)
  else
    GetAutotileSurroundings := (BitFor(X-1, Y-1) shl 7)
                                    or (BitFor(X, Y-1) shl 6)
                                    or (BitFor(X+1, Y-1) shl 5)
                                    or (BitFor(X-1, Y) shl 4)
                                    or (BitFor(X+1, Y) shl 3)
                                    or (BitFor(X-1, Y+1) shl 2)
                                    or (BitFor(X, Y+1) shl 1)
                                    or BitFor(X+1, Y+1);
end;

function TAutotileShaper.TileAt(X, Y: Integer): Integer; inline;
begin
  TileAt := MapData.Integers[(Z * Height + Y) * Width + X];
end;

constructor TAutotileShaper.Create(AMap: TJSONObject; AZ: Integer);
begin
  Map := AMap;
  Width := Map.Integers['width'];
  Height := Map.Integers['height'];
  MapData := Map.Arrays['data'];
  Z := AZ;
  CellsToCheck := TPointList.Create;
end;

destructor TAutotileShaper.Destroy;
begin
  inherited Destroy;
end;

procedure TAutotileShaper.QueueCell(X, Y: Integer);
begin
  if (X >= 0) and (Y >= 0) and (X < Width) and (Y < Height) then
    CellsToCheck.Add(Point(X, Y));
end;

procedure TAutotileShaper.QueueRectangleCells(X1, Y1, X2, Y2: Integer);
  procedure CorrectArgs;
  var
    Tmp: Integer;
  begin
    if X1 > X2 then begin
      Tmp := X2;
      X2 := X1;
      X1 := Tmp;
    end;

    if Y1 > Y2 then begin
      Tmp := Y2;
      Y2 := Y1;
      Y1 := Tmp;
    end;
  end;

  procedure QueueRow(RX1, RX2, RY: Integer);
  var
    RX: Integer;
  begin
    for RX := RX1 to RX2 do
      QueueCell(RX, RY);
  end;

  procedure QueueColumn(RX, RY1, RY2: Integer);
  var
    RY: Integer;
  begin
    for RY := RY1 to RY2 do
      QueueCell(RX, RY);
  end;

  procedure SubRectangle(SubX1, SubY1, SubX2, SubY2: Integer);
  begin
    QueueRow(SubX1, SubX2, SubY1);
    if SubY1 <> SubY2 then
        QueueRow(SubX1, SubX2, SubY2);

    if SubY2 - SubY1 > 1 then begin
      QueueColumn(SubX1, SubY1 + 1, SubY2 - 1);
      QueueColumn(SubX2, SubY1 + 1, SubY2 - 1);
    end;
  end;

begin
  CorrectArgs;

  SubRectangle(X1, Y1, X2, Y2);
  SubRectangle(X1-1, Y1-1, X2+1, Y2+1);
end;

procedure TAutotileShaper.ChangeCells;
var
  Cell: TPoint;
  X, Y, TileId, NewTileId, Shape, ConfigurationIndex: Integer;
begin
  for Cell in CellsToCheck do begin
    X := Cell.X;
    Y := Cell.Y;

    TileId := TileAt(X, Y);
    if IsFloorTypeAutotile(TileId) or IsWallTypeAutotile(TileId) then begin
      ConfigurationIndex := GetAutotileSurroundings(X, Y);
      if IsFloorTypeAutotile(TileId) then
        Shape := FLOOR_AUTOTILE_SHAPE_FROM_SURROUNDINGS[ConfigurationIndex]
      else
        Shape := WALL_AUTOTILE_SHAPE_FROM_SURROUNDINGS[ConfigurationIndex];
      NewTileId := MakeAutotileId(GetAutotileKind(TileId), Shape);
      MapData.Integers[(Z * Height + Y) * Width + X] := NewTileId;
    end else if IsWaterfallTypeAutotile(TileId) then begin
      ConfigurationIndex := GetAutotileSurroundings(X, Y, True);
      Shape := WATERFALL_AUTOTILE_SHAPE_FROM_SURROUNDINGS[ConfigurationIndex];
      NewTileId := MakeAutotileId(GetAutotileKind(TileId), Shape);
      MapData.Integers[(Z * Height + Y) * Width + X] := NewTileId;
    end;
  end;
end;

end.

